function R = C_loadRecording(varargin)
% MAIN ACCESS FUNCTION FOR DATA RECORDED WITH CONTROLLER

P = parsePairs(varargin);
checkField(P,'Animal');
checkField(P,'Recording');
checkField(P,'Modules','all');
checkField(P,'Trials','all');
checkField(P,'Verbose',1)
% FIND THE BASE PATH (COMPARE TO C_initialize)
% will have the format: ../././Path/Animal/R{RNum}/

% CHECK INTEGRITY OF TIME VECTOR FOR LOADING (SINGLE VS DOUBLE AND BACKJUMPS)

[RecordingPath,Paths] = C_getDir('Animal',P.Animal,'Recording',P.Recording);

% LOAD BASIC INFORMATION
R.General = load([RecordingPath,'General.mat']);

% LOAD DIFFERENT PARTS OF THE RESPONSE
if P.Verbose fprintf('\n = = = = = = = LOADING DATA = = = = = = = \n'); end
Modules = {R.General.CGSave.Paradigm.Modules.Name}; AllModules = {};
Types = {R.General.CGSave.Paradigm.Modules.Type};
for iM=1:length(Modules)
  clear Trials;
  cModule = Modules{iM};
  if P.Verbose fprintf(['Processing Module : ',cModule]); end
    
  if ~(ischar(P.Modules) && strcmp(P.Modules,'all')) && ~sum(strcmp(P.Modules,cModule)) fprintf('... skipping\n'); continue; end
  ModulePath = [RecordingPath,cModule,filesep];
  DataFiles = dir([ModulePath,'Data_*.mat']);
  NTrials = length(DataFiles);
  if NTrials == 0; fprintf('\n'); continue; end
  for iF=1:NTrials
    Trials(iF) = str2num(DataFiles(iF).name(6:end-4));
  end
  if strcmp(P.Trials,'all') P.Trials = [1:NTrials]; end;
  Trials = intersect(P.Trials,Trials);
  if P.Verbose && length(Trials) fprintf('\n > Trial : '); end
  R.(cModule).Trials = Trials;
  for iT=1:length(Trials)
    cTrial = Trials(iT);
    if P.Verbose fprintf([' ',num2str(cTrial)]); end
    FileNameRoot = [ModulePath,'Data_',num2str(cTrial)];
    cFileName = [FileNameRoot,'.mat'];
    if exist(cFileName,'file')
      switch cModule
        case 'PointGrey'; 
          R.(cModule).Data(iT) = C_loadVideo(FileNameRoot); 
        otherwise
          R.(cModule).Data(iT) = load(cFileName);
      end
      AllModules{end+1} = cModule;
      switch cModule
        case 'PointGrey';
      end
    else
      if P.Verbose ; fprintf(['M']); end
    end
  end
  fprintf('\n')
end
ModulesFound = unique(AllModules);
[Modules,Ind] = intersect(Modules,ModulesFound);
Types = Types(Ind);

% SYNCHRONIZE THE DIFFERENT CHANNELS
% - Synchronization pulse sent to one of the Arduinos, and received on all other Arduinos on DI0 (Sync. Port.)
% - For Synchronization : 
%     > Arduinos :        Searched for DI0 => 1
%     > Camera :         Synchronization happens at the beginning of the first pulse
%     > AudioIn/Out :   Wire synchronization into an AI which is recorded in parallel to the AudioInOut
%     > Physiology :      Wire synchronization pulse into an DI/AI aside from the other channels
if P.Verbose fprintf('\n = = = = = = = ALIGNING DATA = = = = = = = \n'); end
cModules = setdiff(Modules,'NIDAQ'); Modules = {'NIDAQ',cModules{:}};
for iM=1:length(Modules)   % LOOP OVER MODULES
  cModule = Modules{iM};  cType = Types{iM};
  if P.Verbose fprintf(['Processing Module : ',cModule]); end
  if isfield(R,cModule)
    fprintf('\n > Trial : ');
    cNTrials = length(R.(cModule).Trials);
    for iT = 1:cNTrials % LOOP OVER TRIALS
      cTrial = R.(cModule).Trials(iT);      
      
      % CHECK FOR SYNCING IN OTHER MODULES
      if P.Verbose fprintf([' ',num2str(cTrial)]); end
      
      switch cType
        case {'Arduino'};
          if ~isempty(R.(cModule).Data(iT).Data.Digital)
            ChangePos = find(diff(bitget(R.(cModule).Data.(iT).Data.Digital,1))~=0);
            ChangeVal = bitget(R.(cModule).Data(iT).Data.Digital(ChangePos,1),1);
            ChangeTime = R.(cModule).Data(iT).Data.Time(ChangePos,:); % as datenum
          else
            ChangePos =[]; ChangeVal = []; ChangeTime = [];
          end
        case {'NI'}
          if ~isempty(R.(cModule).Data(iT).Data.Time)
            switch R.(cModule).Data(iT).Session.Saving
              case 'Trial'; % DAQ OBJECT RUNS CONTINUOUSLY, TRIALS ARE CHUNKED  e.g NIDAQ
                switch cModule
                  case 'NIDAQ'; % SYNC PULSE ON CHANNEL
                    Names = {R.General.CGSave.Paradigm.HW.Inputs.Name};
                    
                    % FIND TRIAL START & STOP
                    TrialInd = find(strcmp('Trial',Names));
                    TrialPos = R.General.CGSave.Paradigm.HW.Inputs(TrialInd).Index;
                    ChangeInd = R.(cModule).Data(iT).Data.Analog(:,TrialPos)>2.5;
                    ChangePos = find(diff(ChangeInd)~=0)+1;
                    ChangeTime = R.(cModule).Data(iT).Data.Time(ChangePos,1);
                    ChangeVal = ChangeInd(ChangePos);
                    if length(ChangePos)==1 && iT< cNTrials % CHECK NEXT TRIAL FOR DOWNSTEP OF TRIAL TRIGGER
                      if ~isempty(R.(cModule).Data(iT+1).Data.Time)
                        ChangeIndNext = R.(cModule).Data(iT+1).Data.Analog(:,TrialPos)>2.5;
                        ChangePosNext = find(ChangeIndNext==0,1,'first');
                        ChangeVal(2) = -1;
                        TransInd = [1:ChangePosNext(1)+1];
                        R.(cModule).Data(iT).Data.Analog(end+TransInd,:) =  R.(cModule).Data(iT+1).Data.Analog(TransInd,:);
                        R.(cModule).Data(iT).Data.Time(end+TransInd,:) =  R.(cModule).Data(iT+1).Data.Time(TransInd,:);
                        R.(cModule).Data(iT+1).Data.Analog = R.(cModule).Data(iT+1).Data.Analog(ChangePosNext+2:end,:);
                        R.(cModule).Data(iT+1).Data.Time = R.(cModule).Data(iT+1).Data.Time(ChangePosNext+2:end,:);
                        ChangePos(2) = size(R.(cModule).Data(iT).Data.Time,1)-1;
                        ChangeTime(2) = R.(cModule).Data(iT).Data.Time(end-1,1);
                        if ChangeTime(2) == 0 keyboard; end
                        ChangeVal(2) = -1;
                      end
                    else
                      ChangePos(2) = size(R.(cModule).Data(iT).Data.Time,1);
                      ChangeVal(2) = -1;
                      ChangeTime(2) = R.(cModule).Data(iT).Data.Time(end,1);
                    end                    
               
                    R.(cModule).Data(iT).TrialStartTime= ChangeTime(1);
                    R.(cModule).Data(iT).TrialStopTime= ChangeTime(2);
                   
                    % FIND CAMERA START
                    CameraInd = find(strcmp('CamStart',Names));
                    CameraPos = R.General.CGSave.Paradigm.HW.Inputs(CameraInd).Index;
                    CamChangeInd = R.(cModule).Data(iT).Data.Analog(:,CameraPos)>2.5;
                    CamChangePos = find(diff(CamChangeInd)~=0)+1;
                    cInd = find(CamChangeInd(CamChangePos)==1);
                    CamChangeTime = R.(cModule).Data(iT).Data.Time(CamChangePos,1);
                    
                    R.(cModule).Data(iT).VideoStartTime = CamChangeTime(cInd);
                    
                    
                    
                  case 'AnalogIn';
                    if ~isempty(R.(cModule).Data(iT).Data)
                      ChangePos = 1; ChangeVal = 1;
                      ChangeTime = R.NIDAQ.Data(iT).Sync.SyncTimeRel;
                      R.AnalogIn.Data(iT).Data.Time = LF_fixTime(R.AnalogIn.Data(iT).Data.Time);
                    else
                      ChangeTime = []; ChangePos = []; ChangeVal = [];
                    end
                end
                
              case 'All';    % SAVE ALL ACQUIRED DATA AS TRIAL (E.G. AnalogIn)
                ChangePos = 1;
                ChangeVal = 1;
                if ~isempty(R.(cModule).Data(iT).Data.Time)
                  ChangeTime = R.NIDAQ.Data(iT).Sync.SyncTimeRel;
                  % FIX TIME PROBLEMS
                  switch cModule
                    case 'AnalogIn'; 
                      R.AnalogIn.Data(iT).Data.Time = LF_fixTime(R.AnalogIn.Data(iT).Data.Time);
                  end
                else ChangeTime = NaN;
                end
            end
          else 
               ChangeTime = []; ChangePos = []; ChangeVal = [];
          end
          
        case {'AudioIn','AudioOut'};
          ChangePos = R.(cModule).Data(iT).Sync.ChangePos;
          ChangeVal = R.(cModule).Data(iT).Sync.ChangeVal;
          ChangeTime = R.(cModule).Data(iT).Sync.ChangeTime;
   
        case 'Video';    
          if ~isempty(R.(cModule).Data(iT).Data)
            ChangePos = 1; ChangeVal = 1;
            
            ChangeTime = R.(cModule).Data(iT).Data.Time(ChangePos,1);
          else
            ChangeTime = []; ChangePos = []; ChangeVal = [];
          end
        otherwise error('Module Type not implemented!');
      end
      R.(cModule).Data(iT).Sync.ChangePos = ChangePos;
      R.(cModule).Data(iT).Sync.ChangeVal = ChangeVal;
      R.(cModule).Data(iT).Sync.ChangeTimes = ChangeTime;
      
       % CORRECT TIME VECTOR TO A UNIQUE REFERENCE FRAME 
      % TIME IS REPRESENTED RELATIVE TO START OF PARADIGM
      if ~isempty(ChangePos) 
        switch cModule
          case 'AnalogIn'
            % FIND INITIALIZING SYNC PULSE
            R.(cModule).Data(iT).Sync.SyncTimeRel = R.NIDAQ.Data(iT).TrialStartTime;
          case 'PointGrey';
            % FIND INITIALIZING SYNC PULSE
            R.(cModule).Data(iT).Sync.SyncTimeRel =  R.NIDAQ.Data(1).VideoStartTime(1);
          otherwise
            R.(cModule).Data(iT).Sync.SyncTimeRel = 0;
        end
        if ~isempty( R.(cModule).Data(iT).Data.Time)
          R.(cModule).Data(iT).Data.Time(:,1) = R.(cModule).Data(iT).Data.Time(:,1) + R.(cModule).Data(iT).Sync.SyncTimeRel ;
        end
      end
    end
  end
  fprintf('\n')
end

function Time = LF_fixTime(Time)

Start =Time(1,1);
NTimes = size(Time,1);
End = Start; Pos = NTimes;
while End <= Start;   Pos = Pos - 1;  End =Time(Pos,1); end
End = End + (NTimes-Pos)*(End-Start)/Pos;
Time = linspace(Start,End,NTimes)';
